#include "fwapplication.h"
#include "os/semaphore.h"
#include "os/mutexlocker.h"
#include "frameworkcore.h"
#include "log/logger.h"
#include "os/osapi.h"

FwApplication::FwApplication()
{
    m_thread.SetThreadName("app");
}

FwApplication::~FwApplication()
{
}

FwApplication &FwApplication::Instance()
{
    static FwApplication instance;
    return instance;
}

void FwApplication::SendEvent(ApplicationEvent *event)
{
    //发送，并且不等待
    m_msgQueue.Post(event);
}

//支持中断post
void FwApplication::Post(const APPLICATION_CALLER_FUNC &func)
{
    if(OsApi::IsIRQ())
    {
        //中断中，不能new
        int index;
        auto ret = OsApi::KernelEnterCritical();
        m_threadCallerIndex = (m_threadCallerIndex + 1) % FW_APPLICATION_PREV_EVENT_MAX_SIZE;
        index = m_threadCallerIndex;
        OsApi::KernelExitCritical(ret);
        
        auto event = &m_threadCallerEvents[index];
        event->IsPreAllocated = true;
        event->Func = func;
        SendEvent(event);
    }
    else
    {
        SendEvent(new ThreadCallerEvent(func));
    }
}

void FwApplication::Send(const APPLICATION_CALLER_FUNC &func)
{
    Semaphore sem(0, 1);

    Post([&](){
        func();
        sem.Release();
    });
    sem.Acquire();
}

int FwApplication::CallOnOneShot(const APPLICATION_CALLER_FUNC &func, int period)
{
    return SendTimerCallEventImpl(func, Timer::TimerType::OneShot, period);
}

int FwApplication::CallPeriod(const APPLICATION_CALLER_FUNC &func, int period)
{
    return SendTimerCallEventImpl(func, Timer::TimerType::Period, period);
}

void FwApplication::CallImmediately(int id)
{
    HandleTimer(id);
}

void FwApplication::RemoveCall(int id)
{
    MutexLocker locker(&m_timerEventLock);
    
    auto it = m_timerEventMap.find(id); 
    if (it!= m_timerEventMap.end())
    {
        m_timerEventMap.erase(it);
        delete it->second;
    }
}

bool FwApplication::ExistsCall(int id)
{
    MutexLocker locker(&m_timerEventLock);
    return m_timerEventMap.find(id) != m_timerEventMap.end();
}

bool FwApplication::IsRunning()
{
    return m_thread.IsRunning();
}

void FwApplication::Start()
{
    StartImpl();
    OnLoop();
}

void FwApplication::Shutdown()
{
    if(m_thread.IsRunning())
        m_thread.Stop();
    
    OnShutdown();
}

void FwApplication::OnStartUp()
{
    
}

void FwApplication::OnShutdown()
{
    
}

void FwApplication::OnLoop()
{
}

void FwApplication::OnEvent(ApplicationEvent *event)
{
    FW_UNUSED(event);
}

void FwApplication::HandleTimer(int id)
{
    MutexLocker locker(&m_timerEventLock);

    for(auto it = m_timerEventMap.begin(); it != m_timerEventMap.end(); )
    {
        auto ev = it->second;
        
        //如果指定了id
        if(id >= 0 && ev->Id != id)
            continue;

        bool isDelete = false;
        ev->CurrentMs++;
        if(ev->CurrentMs >= ev->Period)
        {
            ev->CurrentMs = 0;
            if(ev->Func)
            {
                ev->Func();
            }

            if(ev->Type == Timer::TimerType::OneShot)
            {
                it = m_timerEventMap.erase(it);
                isDelete = true;
                delete ev;
            }
        }

        if(!isDelete)
        {
            it ++;
        }

        if(id >= 0)
            break;
    }
}

int FwApplication::SendTimerCallEventImpl(const APPLICATION_CALLER_FUNC &func, Timer::TimerType type, int period)
{
    if(m_timerEventMap.size() > FW_APPLICATION_TIMER_EVENT_MAX_SIZE)
    {
        return -1;
    }
    
    TimerCallerEvent *event = new TimerCallerEvent(func, type, period);
    //
    m_timerEventIdLock.Lock();
    event->Id = m_currentTimerExecId++;
    m_timerEventIdLock.UnLock();
    //
    event->Func = func;
    event->Type = type;
    event->Period = period;
    
    SendEvent(event);
    return event->Id;
}

void FwApplication::HandleEvent(ApplicationEvent *event)
{
    if(event == nullptr)
        return;
    
    OnEvent(event);

    switch(event->Type)
    {
        case ApplicationEventType::ThreadCall:
        {
            auto ev = (ThreadCallerEvent*)event;
            if(ev && ev->Func)
                ev->Func();
            
            if(!ev->IsPreAllocated)
                delete ev;
        }
        break;
        case ApplicationEventType::TimerCall:
        {
            auto ev = (TimerCallerEvent*)event;
            m_timerEventLock.Lock();
            m_timerEventMap[ev->Id] = ev; 
            m_timerEventLock.UnLock();
        }
        break;
        default:
        {
            delete event;
        }
        break;
    }
}

void FwApplication::StartImpl()
{
    m_thread.SetPriority(Thread::ThreadPriority::High);
    if(m_thread.IsRunning())
        return;
    
    //早期board初始化
	__FW_BoardAutoInit();
    
    //自身初始化
    m_thread.Start([=](){
        TaskLoopImpl();
    });

	//日志初始化
    if(LoggerEnable)
    {
        Logger::Instance().Configuration.CurrentLevel = LoggerLevel;
        if(LoggerMode == LoggerWriteMode::ASync)
        {
            Logger::Instance().StartAsync();
        }
    }
    
	//然后是框架
	FW_Init();

	//设备初始化
	__FW_DeviceAutoInit();
	//APP初始化
	__FW_AppAutoInit();
    
    //raise
    OnStartUp();
}

void FwApplication::TaskLoopImpl()
{
    m_timer.SetInterval(FW_APPLICATION_TIMER_INTERVAL);
    m_timer.SetElapsed([=](auto &timer){HandleTimer();});
    m_timer.Start();
    while (m_thread.IsRunning())
    {
        ApplicationEvent *ev = nullptr;
        auto ok = m_msgQueue.Wait(ev);
        if(ok && ev)
        {
            HandleEvent(ev);
        }
    }
}
